package com.corecmd.tcloud.tcimserver.service.impl;

import com.corecmd.tcloud.tcimcommon.im.domain.MessageRequestPacket;
import com.corecmd.tcloud.tcimserver.cache.RedisImCacheManager;
import com.corecmd.tcloud.tcimserver.domain.*;
import com.corecmd.tcloud.tcimserver.enums.*;
import com.corecmd.tcloud.tcimserver.mapper.IFriendMapper;
import com.corecmd.tcloud.tcimserver.mapper.IUserMapper;
import com.corecmd.tcloud.tcimserver.service.IFriendService;
import com.corecmd.tcloud.tcimserver.service.SendMessageToClientsService;
import com.corecmd.tcloud.tcimserver.utils.CustomResponse;
import com.corecmd.tcloud.tcimserver.utils.DateFormatUtil;
import com.corecmd.tcloud.tcimserver.utils.ImCrossServerPushUtil;
import com.corecmd.tcloud.tcimserver.utils.UniqueId;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author : TianShaoJiao
 * @date : 2021/2/26
 * @description :
 **/
@Slf4j
@Service
public class FriendServiceImpl implements IFriendService {
    @Autowired
    private IFriendMapper friendMapper;
    @Value("${imserver.clientKeyPrefix}")
    private String imClientServerPrefix;
    @Value("${imserver.host}")
    private String localImHost;
    @Value("${imserver.port}")
    private String localImPort;
    @Autowired
    private RedisImCacheManager redisImCacheManager;
    @Autowired
    private SendMessageToClientsService sendMessageToClientsService;
    @Autowired
    private IUserMapper userMapper;

    @Override
    public List<ImFriendGroupDTO> getGroups(UserInfoDTO sessionUser,Map<String, Object> query) {
        query.put("userId",sessionUser.getId());
        return friendMapper.getFriendGroups(query);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int addGroup(UserInfoDTO sessionUser, String groupName) {
        ImFriendGroupDO newGroup = new ImFriendGroupDO();
        newGroup.setId(UniqueId.getUniqueId());
        newGroup.setName(groupName);
        newGroup.setOwnerId(sessionUser.getId());
        newGroup.setCreateTime(new Date());
        newGroup.setStatus(AvailableStatusEnum.YES.getCode());
        newGroup.setParentId("0");
        newGroup.setDefaultGroup(AvailableStatusEnum.NO.getCode());
        int maxGroupSortNum = friendMapper.getMaxGroupSortNum(sessionUser.getId());
        maxGroupSortNum += 1;
        newGroup.setSortNum(maxGroupSortNum);
        return friendMapper.addFriendGroup(newGroup);
    }

    @Override
    public int renameGroup(UserInfoDTO sessionUser, String groupId, String newName) {
        Map<String,Object> param = new HashMap<>(3);
        param.put("userId",sessionUser.getId());
        param.put("groupId",groupId);
        param.put("newName",newName);
        return friendMapper.renameGroup(param);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int removeGroup(UserInfoDTO sessionUser, String groupId) {
        int removeResult = 0;
        //获取默认分组列表
        Map<String,Object> query = new HashMap<>();
        query.put("userId",sessionUser.getId());
        query.put("defaultGroup",AvailableStatusEnum.YES.getCode());
        List<ImFriendGroupDTO> defaultGroups = friendMapper.getFriendGroups(query);
        if (defaultGroups != null && defaultGroups.size() > 0){
            //转移好友列表到默认分组
            query.clear();
            query.put("originGroupId",groupId);
            query.put("targetGroupId",defaultGroups.get(0).getId());
            query.put("ownerId",sessionUser.getId());
            friendMapper.switchGroupMembers(query);
            //删除当前分组
            removeResult = friendMapper.deleteGroup(groupId);
        }
        return removeResult;
    }

    /**
     *
     * @param sessionUser 当前用户
     * @param friendInfo 好友信息
     * @param remarkName 备注昵称
     * @param groupId 好友分组id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int addFriend(UserInfoDTO sessionUser, UserInfoDTO friendInfo, String remarkName, String groupId,String extraMessage) {
        int userId = sessionUser.getId();
        int friendId = friendInfo.getId();
        //1、生成好友对象
        ImFriendDO newFriend = new ImFriendDO();
        newFriend.setId(UniqueId.getUniqueId());
        newFriend.setRelationStatus(FriendRelationStatusEnum.UNAGREE.getTypeEn());
        newFriend.setCreateTime(new Date());
        newFriend.setNickName(friendInfo.getUserName());
        newFriend.setRemarkNickName(remarkName);
        newFriend.setGroupId(groupId);
        newFriend.setOwnerId(userId);
        newFriend.setFriendId(friendId);
        int addResult = friendMapper.addFriend(newFriend);
        //2、生成好友申请记录
        ImFriendAddRequestDO requestDO = new ImFriendAddRequestDO();
        requestDO.setId(UniqueId.getUniqueId());
        requestDO.setCreateTime(new Date());
        requestDO.setFriendId(friendId);
        requestDO.setSenderId(userId);
        requestDO.setStatus(FriendRelationStatusEnum.UNAGREE.getTypeEn());
        requestDO.setRemark(extraMessage);
        requestDO.setOwnerId(userId);
        //申请人保存一份
        friendMapper.addFriendRequest(requestDO);
        //被添加人保存一份
        requestDO.setId(UniqueId.getUniqueId());
        requestDO.setOwnerId(friendId);
        friendMapper.addFriendRequest(requestDO);
        //通知对方
        try {
            List<String> friendImInfos = redisImCacheManager.getPrefixKeyValue(imClientServerPrefix + friendId + "_*");
            if (null != friendImInfos && friendImInfos.size() > 0){
                MessageRequestPacket messagePacket = new MessageRequestPacket();
                messagePacket.setReceiverId(String.valueOf(friendId));
                messagePacket.setSenderId(String.valueOf(userId));
                messagePacket.setMsgContent("用户["+sessionUser.getUserName()+"]请求添加您为好友");
                messagePacket.setMsgType(String.valueOf(MessageTypeEnum.SYS_CLIENT.getTypeEn()));
                messagePacket.setMsgContentType(String.valueOf(MessageContentTypeEnum.PLAINTEXT.getTypeEn()));
                messagePacket.setSendTimestamp(DateFormatUtil.getCurrentDateStr());
                for (String clientImInfo:friendImInfos) {
                    try {
                        String []array = clientImInfo.split(":");
                        String imHost = array[0];
                        String imPort = array[1];
                        if (localImHost.equals(imHost) && localImPort.equals(imPort)){
                            //本机推送
                            CustomResponse customResponse = sendMessageToClientsService.sendMessage(messagePacket);
                            log.info("本机推送好友添加请求消息到客户端：{},发送结果：{}",friendId,customResponse != null?customResponse.get("message"):"失败");
                        } else {
                            //跨服务器推送
                            String imHttpPort = array[2];
                            String imProtocol = array[3];
                            Map<String,String> params = new HashMap<String,String>();
                            params.put("senderId",messagePacket.getSenderId());
                            params.put("receiverId",messagePacket.getReceiverId());
                            params.put("msgContent",messagePacket.getMsgContent());
                            params.put("msgType",messagePacket.getMsgType());
                            params.put("msgContentType",messagePacket.getMsgContentType());
                            params.put("sendTimestamp",messagePacket.getSendTimestamp());
                            Map<String,String> headers = new HashMap<String,String>();
                            headers.put("authToken",sessionUser.getAuthToken());
                            String httpUrl = imProtocol+"://" + imHost + ":" + imHttpPort + "/rest/imServer/pushMessage";
                            boolean crossPushResult = ImCrossServerPushUtil.crossServerPush(httpUrl,params,headers);
                            log.info("跨服务器推送好友添加请求消息到客户端：{} {}",friendId,crossPushResult?"成功":"失败");
                        }
                    } catch (Exception e) {
                        log.info("推送添加好友请求消息到服务器：{} 异常",clientImInfo,e);
                    }
                }
            } else {
                log.info("redis没有查询到im记录：{}",friendId);
            }
        } catch (Exception e) {
            log.info("推送IM好友添加请求异常",e);
        }
        return addResult;
    }

    /**
     * 加载好友申请列表
     * @param sessionUser
     * @param query
     * @return
     */
    @Override
    public List<ImFriendAddRequestDTO> listFriendReqs(UserInfoDTO sessionUser, Map<String, Object> query) {
        query.put("userId",sessionUser.getId());
        return friendMapper.listFriendReqs(query);
    }

    /**
     * 处理好友请求
     * @param sessionUser 当前用户
     * @param senderId 发起人
     * @param suggestionEnum 处理意见
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int processFriendAddReq(UserInfoDTO sessionUser, int senderId, FriendAddReqSuggestionEnum suggestionEnum) {
        //1、将当前用户作为被添加人，并且发起人为senderId的好友申请，状态改为 suggestionEnum
        Map<String,Object> params = new HashMap<String, Object>();
        params.put("friendId",sessionUser.getId());
        params.put("senderId",senderId);
        params.put("status",suggestionEnum.getTypeEn());
        int processResult = friendMapper.processFriendAddReq(params);
        /**
         * 若为同意添加，则将当前用户作为发起人，senderId作为被添加人的好友申请状态改为同意
         * 同时，给当前用户和senderId分别添加对方好友信息
         */
        if (FriendAddReqSuggestionEnum.AGREE.getTypeEn().equalsIgnoreCase(suggestionEnum.getTypeEn())){
            params.clear();
            params.put("friendId",senderId);
            params.put("senderId",sessionUser.getId());
            params.put("status",suggestionEnum.getTypeEn());
            friendMapper.processFriendAddReq(params);
            boolean addMe = addFriendToUser(sessionUser.getId(),senderId);
            boolean addHe = addFriendToUser(senderId,sessionUser.getId());
            if (!addMe || !addHe){
                throw new RuntimeException("添加对方为好友时异常");
            }
        } else {
            //删除发起人senderId好友列表中，friendId为当前用户的记录，并且关系状态为： 1：未同意添加
            Map<String,Object> deleteParams = new HashMap<String, Object>();
            deleteParams.put("friendId",sessionUser.getId());
            deleteParams.put("ownerId",senderId);
            deleteParams.put("relationStatus",FriendRelationStatusEnum.UNAGREE.getTypeEn());
            friendMapper.deleteFriend(deleteParams);
        }
        return processResult;
    }

    private boolean addFriendToUser(int ownerId,int friendId){
        log.info(ownerId + "添加用户： "+friendId+" 为好友");
        boolean isSuccess = false;
        UserInfoDTO friendInfo = userMapper.getUserById(friendId);
        //1、先查询ownerId好友列表中是否有对方，若有，则修改关系状态为：正常
        Map<String,Object> query = new HashMap<String, Object>();
        query.put("ownerId",ownerId);
        query.put("friendId",friendId);
        List<ImFriendDTO> friends = friendMapper.getFriends(query);
        if (null != friends && friends.size() > 0){
            log.info("更新用户：" + ownerId + " 的好友列表记录：" + friendId);
            query.put("relationStatus",FriendRelationStatusEnum.NORMAL.getTypeEn());
            int updateResult = friendMapper.updateFriendRelation(query);
            isSuccess = updateResult > 0;
        } else {
            log.info("为用户： " + ownerId + "生成好友记录： " + friendId);
            //2、若没有对方，则生成新记录，放入默认好友分组中
            //获取默认好友分组
            query.clear();
            query.put("userId",ownerId);
            query.put("defaultGroup",AvailableStatusEnum.YES.getCode());
            List<ImFriendGroupDTO> defaultGroups = friendMapper.getFriendGroups(query);
            ImFriendGroupDO defaultFriendGroup = null;
            if (null != defaultGroups && defaultGroups.size() > 0){
                defaultFriendGroup = defaultGroups.get(0);
            } else {
                log.info("用户: " + ownerId + "没有默认好友分组，系统自动生成");
                ImFriendGroupDO newGroup = new ImFriendGroupDO();
                newGroup.setId(UniqueId.getUniqueId());
                newGroup.setName("我的好友");
                newGroup.setOwnerId(ownerId);
                newGroup.setCreateTime(new Date());
                newGroup.setSortNum(0);
                newGroup.setStatus(AvailableStatusEnum.YES.getCode());
                newGroup.setParentId("0");
                newGroup.setDefaultGroup(AvailableStatusEnum.YES.getCode());
                int addResult = friendMapper.addFriendGroup(newGroup);
                defaultFriendGroup = addResult > 0 ? newGroup : null;
            }
            if (null != defaultFriendGroup){
                ImFriendDO newFriend = new ImFriendDO();
                newFriend.setId(UniqueId.getUniqueId());
                newFriend.setRelationStatus(FriendRelationStatusEnum.NORMAL.getTypeEn());
                newFriend.setCreateTime(new Date());
                newFriend.setNickName(friendInfo.getUserName());
                newFriend.setRemarkNickName("");
                newFriend.setGroupId(defaultFriendGroup.getId());
                newFriend.setOwnerId(ownerId);
                newFriend.setFriendId(friendId);
                int addResult = friendMapper.addFriend(newFriend);
                isSuccess = addResult > 0;
            }
        }
        return isSuccess;
    }

    @Override
    public List<ImFriendDTO> getFriends(UserInfoDTO sessionUser, Map<String, Object> query) {
        query.put("ownerId",sessionUser.getId());
        return friendMapper.getFriends(query);
    }

    @Override
    public int deleteFriend(Map<String, Object> deleteParams) {
        return friendMapper.deleteFriend(deleteParams);
    }
}
